﻿// @include "../code/Extend.js"
// @include "../code/Array.js"
// @include "../code/Type.js"
// @include "../extend/Debug.js"
/**
 * @fileOverview 事件绑定工具
 * 
 * @version qinglan_Browser 1.0
 * @static
 * @author wxq wxqqh@qq.com
 */
/**
 * 命名空间
 * 
 * @namespace
 * @type Object
 */
window.qinglan = window.qinglan || {};
/**
 * 事件绑定命名空间
 * 
 * @namespace
 * @type Object
 */
qinglan.Event = qinglan.Event || {};
/**
 * 事件绑定列表
 * 
 * @private
 * @field
 * @type Object
 */
qinglan.Event._listenQueue = {};
/**
 * 事件对象索引id
 * 
 * @type Number
 */
qinglan.Event._eleId = 1;
/**
 * 事件方法索引id
 * 
 * @type Number
 */
qinglan.Event._funId = 1;
/**
 * 键位映射
 * 
 * @public
 * @type Object
 */
qinglan.Event.Keys = {
	BACKSPACE : 8,
	TAB : 9,
	RETURN : 13,
	ESC : 27,
	SPACE : 32,
	LEFT : 37,
	UP : 38,
	RIGHT : 39,
	DOWN : 40,
	DELETE : 46
};
/**
 * 进行事件绑定<br/>
 * 对绑定事件的元素节点增加eventId属性作为事件缓存索引,事件都会缓存在qinglan.Event._listenQueue对象中
 * 
 * @param {Element}
 *            ele 节点元素
 * @param {String}
 *            type 事件类型
 * @param {Function}
 *            fun 事件触发函数
 * @param {Array}
 *            argArray 事件触发函数所需要的参数
 */
qinglan.Event.on = function(ele, type, fun, argArray) {
	if (qinglan.Type.isArray(ele)) {// 进行数组处理
		qinglan.Array.each(ele, function(value) {qinglan.Event.on(ele, type, fun,argArray);});
		return ;
	}
	try {
		// 这里进行一系列的初始化操作,只会进行一次
		!ele.__eventEleId && (ele.__eventEleId = qinglan.Event._eleId++);// 添加事件对象索引ID
		!fun.__eventFunId && (fun.__eventFunId = qinglan.Event._funId++);// 添加方法索引ID
		var eventQueue = qinglan.Event._listenQueue;
		!eventQueue[ele.__eventEleId] && (eventQueue[ele.__eventEleId] = {}); // 初始化监听队列

		var eventFun = eventQueue[ele.__eventEleId][fun.__eventFunId] = function(e) {
			fun.apply(ele, !argArray ? [qinglan.Event.getEvent(e)] : [qinglan.Event.getEvent(e)].concat(argArray));
		};

		if (ele.addEventListener) {
			ele.addEventListener(type, eventFun, false);
		} else if (ele.attachEvent) {
			// 适用用IE浏览器
			ele.attachEvent('on' + type, eventFun);
		}
		return true;
	} catch (e) {
		qinglan.Debug.error('Add the fun : [' + fun + '] into listenQueue failed!!');
	}
};
/**
 * 移除事件绑定
 * 
 * @param {Element}
 *            ele 节点元素
 * @param {String}
 *            type 事件类型
 * @param {Function}
 *            fun 事件触发函数
 */
qinglan.Event.remove = function(ele, type, fun) {
	if (qinglan.Type.isArray(ele)) {// 进行数组处理
		qinglan.Array.each(ele, function(value) {
					qinglan.Event.remove(ele, type, fun);
				});
	}
	var eventQueue = qinglan.Event._listenQueue;
	try {
		var eventFun = eventQueue[ele.__eventEleId][fun.__eventFunId];
		if (ele.removeEventListener) {
			ele.removeEventListener(type, eventFun);
		} else {
			ele.detachEvent('on' + type, eventFun);
		}
		return delete eventQueue[ele.__eventEleId][fun.__eventFunId];
	} catch (e) {
		qinglan.Debug.error('The fun : [' + fun + '] is not in the listenQueue !!');
	}
};
/**
 * 获取事件对象
 * 
 * @param {Event}
 *            event 事件源
 * @return {Event}
 */
qinglan.Event.getEvent = function(event) {
	return window.event || event;
};
/**
 * 得到触发事件元素
 * 
 * @param {Event}
 *            event 事件源
 * @return {Element}
 */
qinglan.Event.getTarget = function(event) {
	event = qinglan.Event.getEvent(event);
	return event.srcElement || e.target;
};
/**
 * 禁止默认行为
 * 
 * @param {Event}
 *            event 事件源
 */
qinglan.Event.preventDefault = function(event) {
	event = qinglan.Event.getEvent(event);
	if (event.preventDefault) {
		event.preventDefault();
	} else {
		event.returnValue = false;
	}
};
/**
 * 得到鼠标坐标
 * 
 * @param {Event}
 *            event 事件源 p
 * @return {Object} 鼠标坐标x,y
 */
qinglan.Event.getMousePosition = function(event) {
	event = qinglan.Event.getEvent(event);
	var de = document.documentElement;
	var db = document.body;
	return {
		x : event.pageX || (event.clientX + (de.scrollLeft || db.scrollLeft)),
		y : event.pageY || (event.clientY + (de.scrollLeft || db.scrollLeft))
	};
};
/**
 * 禁止冒泡
 * 
 * @param {Event}
 *            event 事件源
 */
qinglan.Event.cancelBubble = function(event) {
	event = qinglan.Event.getEvent(event);
	if (event.stopPropagation) {
		event.stopPropagation();
	} else {
		if (!event.cancelBubble) {
			event.cancelBubble = true;
		}
	}
};

/**
 * 鼠标悬停函数兼容
 * 
 * @param {Element}
 *            ele 节点元素
 * @param {Function}
 *            fnOver 鼠标进入事件触发函数
 * @param {Function}
 *            fnOut 鼠标离开事件触发函数
 * @param {Array}
 *            argArray 事件触发函数所需要的参数
 */
qinglan.Event.hover = function(ele, fnOver, fnOut, argArray) {
	qinglan.Event.mouseOver(ele, fnOver, argArray);
	qinglan.Event.mouseOut(ele, fnOut, argArray);
};
/**
 * 鼠标进入函数兼容
 * 
 * @param {Element}
 *            ele 节点元素
 * @param {Function}
 *            fun 事件触发函数
 * @param {Array}
 *            argArray 事件触发函数所需要的参数
 */
qinglan.Event.mouseEnter = function(ele, fun, argArray) {
	qinglan.Event.mouseOver(ele, fun, argArray);
};
/**
 * 鼠标离开函数兼容
 * 
 * @param {Element}
 *            ele 节点元素
 * @param {Function}
 *            fun 事件触发函数
 * @param {Array}
 *            argArray 事件触发函数所需要的参数
 */
qinglan.Event.mouseLeave = function(ele, fun, argArray) {
	qinglan.Event.mouseOut(ele, fun, argArray);
};

/**
 * 初始化事件绑定 <br/>只会调用一次
 * 
 * @field
 * @private
 * @type Boolean
 */
qinglan.Event._init = (function() {
	// 添加事件
	qinglan.Array.each(['click', 'mouseDown', 'mouseUp', 'mouseOver',
					'mouseMove', 'mouseOut', 'focus', 'blur', 'keyDown',
					'keyPress', 'keyUp'], function(value) {
				this[value] = function(ele, fun, argArray) {
					return qinglan.Event.on(ele, value.toLocaleLowerCase(),
							fun, argArray);
				};
			}, qinglan.Event);
	// 删除事件
	qinglan.Array.each(['reClick', 'reMouseDown', 'reMouseUp', 'reMouseOver',
					'reMouseMove', 'reMouseOut', 'reFocus', 'reBlur',
					'reKeyDown', 'reKeyPress', 'reKeyUp'], function(value) {
				this[value] = function(ele, fun) {
					return qinglan.Event.remove(ele, value.toLowerCase()
									.slice(2), fun);
				};
			}, qinglan.Event);
	return true;
})();
